/*--------------------------------------------------------------------------*
 | Modification Logs:
 | DATE          AUTHOR     DESCRIPTION
 | ------------------------------------------------
 | Sep 13, 2006      TungNQ     First Creation
 *--------------------------------------------------------------------------*/

package com.aptech.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author tungnq
 * 
 */
public abstract class DateUtils {

    /**
     * 
     * @author tungnq
     * 
     */
    public interface Formats {
        String STR_DATE_TIME_FORMAT = "dd/MM/yyyy HH:mm:ss";

        String STR_DATE_TIME_FORMAT_ORACLE = "dd/mm/yyyy hh24:Mi:ss";

        String STR_DATE_TIME_FORMAT_DDMMYYYY = "dd/MM/yyyy";

        String STR_DATE_TIME_FORMAT_DDMMYYYY_HHMMAM = "dd/MM/yyyy hh:mm a";

        String STR_TIME_FORMAT = "hh:mm a";

        String STR_DATE_TIME_FORMAT_MMDDYYYY = "mm/dd/yyyy";

        String STR_DATE_TIME_FORMAT_YYYYMMDD = "yyyy/MM/dd";

        String STR_DATE_TIME_FORMAT_YYYYMMDD1 = "yyyy-MM-dd";

        String STR_GMT_TIME_ZONE = "GMT";
    }

    /**
     * 
     * @author tungnq
     * 
     */
    public interface Patterns {
        String DATE_DDYYMMM_PATTERN = "[0-3][0-9][0-1][0-9][0-9]{4}";

        String DATE_DDMMYYY_SEPARATOR_PATTERN_1 = "[0-3][0-9]-[0-1][0-9]-[0-9]{4}";

        String DATE_DDMMYYY_SEPARATOR_PATTERN_2 = "[0-3][0-9]/[0-1][0-9]/[0-9]{4}";

        String DATE_YYYYMMDD_SEPARATOR_PATTERN_1 = "[0-9]{4}/[0-1][0-9]/[0-3][0-9]";
    }

    /**
     * 
     * @param str
     * @param pattern
     * @return
     */
    public static boolean isValidPattern(String str, String pattern) {
        if (str == null || pattern == null) {
            return false;
        }
        try {
            Pattern p = Pattern.compile(pattern);
            Matcher m = p.matcher(str);
            return m.find();
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 
     * @return
     */
    public static int getCurrentYear() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        return cal.get(Calendar.YEAR);  
    }
    
    /**
     * 
     * @return
     * @throws Exception
     */
    public static Date getCurrentDate() {
        return new Date();
    }

    /**
     * 
     * @param s
     * @return
     * @throws Exception
     */
    public static Date stringToDate(String s) {
        return stringToDate(s, TimeZone.getDefault());
    }

    /**
     * dateITA has format dd/MM/yyyy
     * 
     * @param s
     * @return
     */
    public static Date stringToDateITA(String s) {
        try {
            if (s != null & s.length() > 0) {
                return stringToDate(s, Formats.STR_DATE_TIME_FORMAT_DDMMYYYY);
            }
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * dateITA has format dd/MM/yyyy
     * 
     * @param s
     * @return
     */
    public static String dateToStringITA(Date date) {
        try {
            if (date != null) {
                return dateToString(date, Formats.STR_DATE_TIME_FORMAT_DDMMYYYY);
            }
        } catch (Exception e) {
        }
        return "";
    }

    /**
     * 
     * @param s
     * @param timeZone
     * @return
     * @throws Exception
     */

    public static Date stringToDate(String s, String pattern) {
        try {
            DateFormat formatter = new SimpleDateFormat(pattern);
            formatter.setLenient(false);
            return formatter.parse(s);
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 
     * @param s
     * @param timeZone
     * @return
     * @throws FunctionalException
     */
    public static Date stringToDate(String s, TimeZone timeZone) {
        try {
            DateFormat formatter = new SimpleDateFormat(Formats.STR_DATE_TIME_FORMAT);
            formatter.setLenient(false);
            formatter.setTimeZone(timeZone);
            return formatter.parse(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 
     * @param stringDate
     * @return
     * @throws SystemException
     */
    public static Date stringToDateFormat(String stringDate) {
        final String LOCATION = ".stringToDateTime(" + stringDate + ", " + Formats.STR_DATE_TIME_FORMAT + ")";
        if (stringDate == null || stringDate.trim().length() == 0) {
            return null;
        } else {
            try {
                SimpleDateFormat fm = new SimpleDateFormat(Formats.STR_DATE_TIME_FORMAT);
                fm.setLenient(false);
                return fm.parse(stringDate.trim());
            } catch (ParseException e) {
            }
        }
        return null;
    }

    /**
     * Convert Date to String according to date pattern
     * 
     * @param date
     *            Date need to convert to String
     * @return String of date converted based on the pattern
     */
    public static String dateToString(Date date) {
        return dateToString(date, Formats.STR_DATE_TIME_FORMAT);
    }

    /**
     * 
     * @param date
     * @param format
     * @return
     * @throws Exception
     */
    public static String dateToString(Date date, String format) {
        try {
            if (date == null) {
                return "";
            }
            SimpleDateFormat fm = new SimpleDateFormat(format);
            return fm.format(date);
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 
     * @param date
     * @param format
     * @return
     * @throws Exception
     */
    public static String dateToString(Calendar cal, String format) {
        Date date = DateUtils.getCalendarDate(cal);
        try {
            SimpleDateFormat fm = new SimpleDateFormat(format);
            return fm.format(date);
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 
     * @return
     * @throws Exception
     */
    public static String GMTTime() {
        return GMTTime(new Date());
    }

    /**
     * 
     * @param date
     * @return
     * @throws Exception
     */
    public static String GMTTime(Date date) {
        return GMTTime(date, Formats.STR_DATE_TIME_FORMAT);
    }

    /**
     * 
     * @param date
     * @param format
     * @return
     * @throws Exception
     */
    public static String GMTTime(Date date, String format) {
        return GMTTime(date, TimeZone.getTimeZone(Formats.STR_GMT_TIME_ZONE), format);
    }

    /**
     * Get GMT Time
     * 
     * @param date
     * @param timezone
     * @param format
     * @return
     * @throws Exception
     */
    public static String GMTTime(Date date, TimeZone timezone, String format) {
        try {
            DateFormat formatter = new SimpleDateFormat(format);
            formatter.setTimeZone(timezone);
            return formatter.format(date);
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * Convert a long to GMT
     */
    public static long toGMT(long longDate) {
        return (toGMT(new Date(longDate))).getTime();
    }

    /**
     * Convert the input date to GMT date
     * 
     * @param date
     *            the date to be converted
     * @return date The converted date object
     * @throws FunctionalException
     */
    public static Date toGMT(Date date) {
        return toGMT(date, TimeZone.getTimeZone(Formats.STR_GMT_TIME_ZONE), Formats.STR_DATE_TIME_FORMAT);
    }

    /**
     * Convert the input date to GMT date
     * 
     * @param date
     *            the date to be converted
     * @return date The converted date object
     * @throws Exception
     */
    public static Date toGMT(Date date, String format) {
        return toGMT(date, TimeZone.getTimeZone(Formats.STR_GMT_TIME_ZONE), format);
    }

    /**
     * Convert the input date to GMT date
     * 
     * @param date
     * @param timezone
     * @param format
     * @return
     * @throws FunctionalException
     */
    public static Date toGMT(Date date, TimeZone timezone, String format) {
        // Create a datetime format
        SimpleDateFormat ds = new SimpleDateFormat(format);
        // Sets the timezone of the datetime format object to GMT
        ds.setTimeZone(timezone);
        return stringToDate(ds.format(date));
    }

    /**
     * Convert form GMT to ITC date
     * 
     * @param date
     * @return
     * @throws Exception
     */
    public static Date GMTToDate(Date date) {
        return GMTToDate(date, TimeZone.getTimeZone(Formats.STR_GMT_TIME_ZONE), Formats.STR_DATE_TIME_FORMAT);
    }

    /**
     * Convert form GMT to ITC date
     * 
     * @param date
     * @param format
     * @return
     * @throws Exception
     */
    public static Date GMTToDate(Date date, String format) {
        return GMTToDate(date, TimeZone.getTimeZone(Formats.STR_GMT_TIME_ZONE), format);
    }

    /**
     * Convert form GMT to ITC date
     * 
     * @param date
     * @param timezone
     * @param format
     * @return
     * @throws Exception
     */
    public static Date GMTToDate(Date date, TimeZone timezone, String format) {
        try {
            DateFormat formatter = new SimpleDateFormat(format);
            formatter.setTimeZone(timezone);
            String str = dateToString(date);
            return formatter.parse(str);
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 
     * @param dateToAdd
     * @param numberOfDayToAdd
     * @return
     */
    public static Date addDay(Date dateToAdd, int numberOfDayToAdd) {
        if(dateToAdd != null) {
            Calendar c1 = Calendar.getInstance();
            c1.setTime(dateToAdd);
            c1.add(Calendar.DAY_OF_MONTH, numberOfDayToAdd);
            return c1.getTime();   
        }
        return dateToAdd;
    }

    /**
     * 
     * @param dateToAdd
     * @param numberOfDateToAdd
     * @return
     */
    public static Date addMonth(Date dateToAdd, int numberOfDateToAdd) {
        if(dateToAdd != null) {
            Calendar c1 = Calendar.getInstance();
            c1.setTime(dateToAdd);
            c1.add(Calendar.MONTH, numberOfDateToAdd);            
            return c1.getTime();
        } 
        return dateToAdd;
    }

    /**
     * 
     * @param calendarToAdd
     * @param numberOfYearToAdd
     * @return
     */
    public static Date addYear(Date dateToAdd, int numberOfYearToAdd) {
        if(dateToAdd != null) {
            Calendar c1 = Calendar.getInstance();
            c1.setTime(dateToAdd);
            c1.add(Calendar.YEAR, numberOfYearToAdd);            
            return c1.getTime();
        }
        return dateToAdd;
    }

    /**
     * 
     * @param cal
     * @return
     */
    public static Date getCalendarDate(Calendar cal) {
        return (cal == null || cal.getTime() == null ? null : cal.getTime());
    }

    /**
     * 
     * @param date
     * @return
     */
    public static Date getCalendarDate(Date date) {
        return date == null ? null : date;
    }

    /**
     * 
     * @param value
     * @return
     */
    public static Calendar getCalendar(Date date) {
        if (date != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(getCalendarDate(date));
            return cal;
        } else {
            return null;
        }
    }

    /**
     * 
     * @param cal1
     * @param cal2
     * @return
     */
    public static boolean equals(Calendar cal1, Calendar cal2) {
        Date date1 = (cal1 == null ? null : cal1.getTime());
        Date date2 = (cal2 == null ? null : cal2.getTime());
        return equals(date1, date2);
    }

    /**
     * 
     * @param cal1
     * @param date2
     * @return
     */
    public static boolean equals(Date date1, Calendar cal2) {
        Date date2 = (cal2 == null ? null : cal2.getTime());
        return equals(date1, date2);
    }

    /**
     * 
     * @param cal1
     * @param date2
     * @return
     */
    public static boolean equals(Calendar cal1, Date date2) {
        Date date1 = (cal1 == null ? null : cal1.getTime());
        return equals(date1, date2);
    }

    /**
     * 
     * @param date1
     * @param date2
     * @return
     */
    public static boolean equals(Date date1, Date date2) {
        return (date1 == null || date2 == null ? false : date1.equals(date2));
    }

    /**
     * 
     * @param date1
     * @param date2
     * @return -1 if date1 < date2 0 if date1 = date2 1 if date1 > date2
     */
    public static int compare2Dates(Date date1, Date date2) {

        Calendar c1 = Calendar.getInstance();
        c1.setTime(date1);

        Calendar c2 = Calendar.getInstance();
        c2.setTime(date2);
        // System.out.println("------------> " + date1 + " : " + c1.getTime() +
        // " : " + c2.getTime());
        if (c1.before(c2)) {
            return -1;
        } else if (c1.after(c2)) {
            return 1;
        } else if (c1.equals(c2)) {
            return 0;
        }
        return 0;
    }

    /**
     * 
     * @param today
     * @return
     */
    public static Date getBeginDay(Date today) {
        if (today != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(today);
            cal.set(Calendar.HOUR_OF_DAY, 0);
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.SECOND, 0);
            cal.set(Calendar.MILLISECOND, 0);
            return cal.getTime();
        }
        return today;
    }

    /**
     * 
     * @param today
     * @return
     */
    public static Date getEndDay(Date today) {
        if (today != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(today);
            cal.set(Calendar.HOUR_OF_DAY, 23);
            cal.set(Calendar.MINUTE, 59);
            cal.set(Calendar.SECOND, 59);
            cal.set(Calendar.MILLISECOND, 0);
            return cal.getTime();
        }
        return today;
    }

    /**
     * @return
     */
    public static Date getFromDate() {
        Date currentDate = getCurrentDate();
        return addYear(currentDate, -1000);
    }

    /**
     * @return
     */
    public static Date getToDate() {
        Date currentDate = getCurrentDate();
        return addYear(currentDate, 1000);
    }

    public static final SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");

    /**
     * Format date in format: yyyy/MM/dd
     * 
     * @param date:
     *            a Date to format
     * @return String represent a date
     */
    public static String toString(Date date) {
        if (date == null)
            return "";
        return df.format(date);
    }

    /**
     * Parse a Date from a string in format: yyyy/MM/dd
     * 
     * @param s
     * @return data
     * @throws Exception
     */
    public static Date parseDate(String s) throws Exception {
        if (s == null)
            return null;
        try {
            return df.parse(s);
        } catch (Exception e) {
            throw new Exception("Cannot parse string " + s + "to Date!");
        }
    }

    /**
     * It uses to compare to time (hour, minute, second)
     * 
     * @param time1
     * @param time2
     * @return 0: time1 == time2 1: time1 > time2 -1: time1 < time2
     */
    public static int compareTime(Date time1, Date time2) {
        if (time1 != null && time2 != null) {
            Calendar cal1 = Calendar.getInstance();
            Calendar cal2 = Calendar.getInstance();

            cal1.setTime(time1);
            int second1 = cal1.get(Calendar.SECOND);
            int minute1 = cal1.get(Calendar.MINUTE);
            int hour1 = cal1.get(Calendar.HOUR_OF_DAY);
            long totalTime1 = (hour1 * 60 * 60) + (minute1 * 60) + (second1);

            cal2.setTime(time2);
            int second2 = cal2.get(Calendar.SECOND);
            int minute2 = cal2.get(Calendar.MINUTE);
            int hour2 = cal2.get(Calendar.HOUR_OF_DAY);
            long totalTime2 = (hour2 * 60 * 60) + (minute2 * 60) + (second2);

            return (totalTime1 == totalTime2 ? 0 : (totalTime1 > totalTime2 ? 1 : -1));
        } else {
            return (time1 == null ? (time2 == null ? 0 : -1) : (time2 == null ? 1 : 0));
        }
    }

    /**
     * 
     * @param startDate
     * @param endDate
     * @return
     */
    public static boolean checkBetween(Date checkDate, Date startDate, Date endDate) {
        if(checkDate != null) {
            long lstartDate = (startDate == null ? Long.MIN_VALUE : startDate.getTime());
            long lendDate = (endDate == null ? Long.MAX_VALUE : endDate.getTime());
            long lcurrDate = checkDate.getTime();            
            
            return (lcurrDate >= lstartDate && lcurrDate <=lendDate);
        }
        return false;
    }
    
    /**
     * 
     * @param strTime
     *            formated 24HH:MM:SS (08:30:23)
     * @return
     */
    public static Date convert2Time(String strTime) {
        try {
            Calendar cal = Calendar.getInstance();
            cal.set(Calendar.MILLISECOND, 0);
            cal.set(Calendar.SECOND, 0);
            cal.set(Calendar.MINUTE, 0);
            cal.set(Calendar.HOUR_OF_DAY, 0);
            if (strTime != null && strTime.length() > 0) {
                StringTokenizer strToken = new StringTokenizer(strTime, ":,; ");
                int ncount = 0;
                String str;
                while (strToken.hasMoreTokens()) {
                    str = strToken.nextToken();
                    switch (ncount) {
                    case 0: /* process hour */
                        cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(str));
                        break;
                    case 1: /* process minute */
                        cal.set(Calendar.MINUTE, Integer.parseInt(str));
                        break;
                    case 2: /* process second */
                        cal.set(Calendar.SECOND, Integer.parseInt(str));
                        break;
                    }
                    ncount++;
                }
            }
            return cal.getTime();
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 
     * @param strTime
     *            formated 24HH:MM:SS (08:30:23)
     * @return
     */
    public static Calendar convert2CalTime(String strTime) {
        Date time = convert2Time(strTime);
        if (time != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(time);
            return cal;
        } else {
            return null;
        }
    }

    /**
     * Check str to date is a validate date after welform format of date
     * 
     * @param dateStr
     * @param pattern
     * @return
     */
    public static boolean isValidateDate(String dateStr, String format) {
        try {
            DateUtils.stringToDate(dateStr, format);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    public static void main(String[] args) {
        try {

            // Date toDay = new Date(System.currentTimeMillis());
            // System.out.println("Current Date=" + toDay);
            // Date GMTDate = toGMT(toDay);
            // System.out.println("GMT Date=" + GMTDate);
            //
            // String date2String = dateToString(GMTDate);
            // System.out.println("GMTDate:date2String =" + date2String);
            // Date string2Date = stringToDate(date2String);
            // System.out.println("GMTDate:string2Date =" + string2Date);
            //
            // System.out.println("GMTToDate =" + GMTToDate(string2Date));
            //
            // String str = GMTTime(toDay);
            // System.out.println("get GMT time=" + str);
            //
            // String time = "30/30/2005 8:8:8";
            // System.out.println("stringToDate(time)=" + stringToDate(time));

            // Date dateOfBirth = DateUtils.stringToDate("28/09/1981",
            // Formats.STR_DATE_TIME_FORMAT_MMDDYYYY);
            // dateOfBirth = addYears(dateOfBirth, 1);
            // Date currentDate = DateUtils.getCurrentDate();
            // System.out.println("----------->" + compare2Dates(dateOfBirth,
            // currentDate));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
